package client

import (
	"context"
	"encoding/json"
	"errors"

	"github.com/astaxie/beego/logs"
)

var uuid uint16 = 0

func getid() uint16 {
	uuid = (uuid + 1) % 0xffff
	return uuid
}

func (c *ClientSession) CallSync(callWay string, sendData any, recvData any) error { //第三个参数必须是指针
	//组装数据进行发下哦那个
	var sendPkg SendData

	sendPkg.Callway = callWay

	tmpStringData, _ := json.Marshal(sendData)
	sendPkg.Data = string(tmpStringData)

	//获得唯一id,并创建指定的channel

	ClientMsgHandleMapInstance.Mtx.Lock()
	id := getid()
	ClientMsgHandleMapInstance.ChannelMap[id] = make(chan []byte) //不需要缓冲区
	ClientMsgHandleMapInstance.Mtx.Unlock()
	//defer移除对应的channel
	defer func() {
		ClientMsgHandleMapInstance.Mtx.Lock()
		delete(ClientMsgHandleMapInstance.ChannelMap, id) //移除id
		ClientMsgHandleMapInstance.Mtx.Unlock()
	}()
	//进行一个发送
	ByteSendPkg, err := json.Marshal(sendPkg) //为什么会有err这个返回值,难道会出错，哪些情况会出错？与绑定的tag有关吗？
	if err != nil {
		logs.Error("[client.go:40]:json.Marshal err:", err)
		return err
	}
	clientSendMsg(id, uint32(len(ByteSendPkg)), ByteSendPkg, c)

	//等待对应的channel触发就好了
	byteCallResult, ok := <-ClientMsgHandleMapInstance.ChannelMap[id]
	if !ok {
		return errors.New("channel closed and not get response")
	}

	var structCallResult ResponseData
	err = json.Unmarshal(byteCallResult, &structCallResult)
	if err != nil {
		logs.Error("[rpcFuncCall.go:62]:json.Unmarshal err:", err)
	}
	//err = DeserializeFunc(structCallResult.Data, recvData)
	json.Unmarshal(structCallResult.Data, recvData)
	if err != nil {
		logs.Error("[rpcFuncCall.go:66]:反序列化到结构体中错误:", err)
		return err
	}
	return nil
}

// 超时调用
func (c *ClientSession) CallSyncWithTimeOut(ctx context.Context, callWay string, sendData any, recvData any) error {
	//组装数据进行发下哦那个
	var sendPkg SendData

	sendPkg.Callway = callWay

	tmpStringData, _ := json.Marshal(sendData)
	sendPkg.Data = string(tmpStringData)

	//获得唯一id,并创建指定的channel

	ClientMsgHandleMapInstance.Mtx.Lock()
	id := getid()
	ClientMsgHandleMapInstance.ChannelMap[id] = make(chan []byte) //不需要缓冲区
	ClientMsgHandleMapInstance.Mtx.Unlock()
	//defer移除对应的channel
	defer func() {
		ClientMsgHandleMapInstance.Mtx.Lock()
		delete(ClientMsgHandleMapInstance.ChannelMap, id) //移除id
		ClientMsgHandleMapInstance.Mtx.Unlock()
	}()
	//进行一个发送
	ByteSendPkg, err := json.Marshal(sendPkg) //为什么会有err,难道会出错，哪些情况会出错？与绑定的tag有关吗？
	if err != nil {
		logs.Error("[client.go:40]:json.Marshal err:", err)
		return err
	}
	clientSendMsg(id, uint32(len(ByteSendPkg)), ByteSendPkg, c)

	//采用select
	select {
	case <-ctx.Done():
		return errors.New("time out")
	case byteCallResult, ok := <-ClientMsgHandleMapInstance.ChannelMap[id]:
		if !ok {
			return errors.New("channel closed and not get response")
		}

		var structCallResult ResponseData
		err = json.Unmarshal(byteCallResult, &structCallResult)
		if err != nil {
			logs.Error("[rpcFuncCall.go:62]:json.Unmarshal err:", err)
		}
		err = json.Unmarshal(structCallResult.Data, recvData)
		if err != nil {
			logs.Error("[rpcFuncCall.go:66]:反序列化到结构体中错误:", err)
			return err
		}
		return nil
	}

}

func (c *ClientSession) CallAsyncWithTimeOut(ctx context.Context, callWay string, sendData any, recvData any, handlerFunc func(recvData any)) error {
	//组装数据进行发下哦那个
	var sendPkg SendData

	sendPkg.Callway = callWay

	tmpStringData, _ := json.Marshal(sendData)
	sendPkg.Data = string(tmpStringData)

	//获得唯一id,并创建指定的channel

	ClientMsgHandleMapInstance.Mtx.Lock()
	id := getid()
	ClientMsgHandleMapInstance.ChannelMap[id] = make(chan []byte) //不需要缓冲区
	ClientMsgHandleMapInstance.Mtx.Unlock()

	//进行一个发送
	ByteSendPkg, err := json.Marshal(sendPkg) //为什么会有err,难道会出错，哪些情况会出错？与绑定的tag有关吗？
	if err != nil {
		logs.Error("[client.go:40]:json.Marshal err:", err)
		return err
	}
	clientSendMsg(id, uint32(len(ByteSendPkg)), ByteSendPkg, c)

	//开启一个协程去异步接收数据，然后
	go func() {
		defer func() {
			ClientMsgHandleMapInstance.Mtx.Lock()
			delete(ClientMsgHandleMapInstance.ChannelMap, id)
			ClientMsgHandleMapInstance.Mtx.Unlock()
		}()
		select {
		case <-ctx.Done():

			return
		case byteResult, ok := <-ClientMsgHandleMapInstance.ChannelMap[id]:
			if !ok {
				logs.Error("[rpcFuncCall.go:117]:channel closed and not get response")
				return
			}
			//处理数据
			var structCallResult ResponseData
			err = json.Unmarshal(byteResult, &structCallResult)
			if err != nil {
				logs.Error("[rpcFuncCall.go:62]:json.Unmarshal err:", err)
			}
			err := json.Unmarshal(structCallResult.Data, recvData)
			if err != nil {
				logs.Error("[rpcFuncCall.go:66]:反序列化到结构体中错误:", err)
				return
			}
			handlerFunc(recvData)
		}
	}()

	return nil
}
